﻿
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Simulator
{
	abstract class WirePoint
	{
		public readonly Wire Wire;

		protected WirePoint (Wire wire)
		{
			this.Wire = wire;
		}

		public abstract Point Location { get; }
	}

	class WirePointPort : WirePoint
	{
		public readonly Port Port;

		public WirePointPort (Wire wire, Port port)
			: base (wire)
		{
			this.Port = port;
		}

		public override Point Location
		{
			get { return Port.ConnectorLocation; }
		}
	}

	class WirePointFree : WirePoint
	{
		Point _location;

		public WirePointFree (Wire wire, Point location)
			: base (wire)
		{
			_location = location;
		}

		public override Point Location
		{
			get { return _location; }
		}
	}

	sealed class Wire
	{
		//public static readonly Pen WirePen = new Pen (Color.Brown, 2);
		public static readonly Pen ForwardingWirePen = new Pen (Color.Green, 4);
		public static readonly Pen TempWirePen = new Pen (Color.Blue, 2);
		public static readonly Pen NoForwardingWirePen = new Pen (Color.Gray, 2) { DashStyle = DashStyle.Dash, DashPattern = new float [] { 8, 8 } };

		const int GrabHandleRectSize = 6;

		readonly List<WirePoint> _points;

		public Wire (Port startPort, Port endPort)
		{
			if (startPort == null)
				throw new ArgumentNullException ("startPort");

			if (endPort == null)
				throw new ArgumentNullException ("endPort");

			_points = new List<WirePoint> ();
			_points.Add (new WirePointPort (this, startPort));
			_points.Add (new WirePointPort (this, endPort));
		}

		public IList<WirePoint> Points { get { return _points; } }

		// TODO: change vlan number to int
		public void Paint (Graphics g, ushort selectedVlanNumber)
		{
			Pen pen = NoForwardingWirePen;

			// If both ends are forwarding, make the wire thick.
			if ((_points [0] is WirePointPort) && (_points [_points.Count - 1] is WirePointPort))
			{
				WirePointPort first = (WirePointPort) _points [0];
				WirePointPort last = (WirePointPort) _points [_points.Count - 1];

				byte firstPointTreeIndex = first.Port.Bridge.Wrapper.GetTreeIndexFromVlanNumber (selectedVlanNumber);
				byte lastPointTreeIndex = last.Port.Bridge.Wrapper.GetTreeIndexFromVlanNumber (selectedVlanNumber);

				if (first.Port.Trees [firstPointTreeIndex].forwarding
					&& last.Port.Trees [lastPointTreeIndex].forwarding)
				{
					pen = ForwardingWirePen;
				}
			}

			Point start = _points [0].Location;

			for (int i = 1; i < _points.Count; i++)
			{
				Point end = _points [i].Location;
				g.DrawLine (pen, start, end);

				Rectangle grabHandleRect = new Rectangle (
					(int) ((start.X + end.X) / 2 - GrabHandleRectSize / 2),
					(int) ((start.Y + end.Y) / 2 - GrabHandleRectSize / 2),
					(int) GrabHandleRectSize,
					(int) GrabHandleRectSize);

				ControlPaint.DrawGrabHandle (g, grabHandleRect, true, true);

				start = end;
			}
		}
	}
}
